home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / tptc16.zip / TPCSCAN.INC < prev    next >
Text File  |  1993-01-04  |  16KB  |  665 lines

  1.  
  2. (*
  3.  * TPTC - Turbo Pascal to C translator
  4.  *
  5.  * (C) 1988 Samuel H. Smith (rev. 13-Feb-88)
  6.  *
  7.  *)
  8.  
  9.  
  10. (********************************************************************)
  11. (*
  12.  * lexical scanner
  13.  *
  14.  *)
  15.  
  16. function coctal(n: integer): anystring;
  17.    {convert an integer into a c style octal character literal}
  18.    function odigit(n: integer): char;
  19.       (* convert an integer into an octal digit *)
  20.    begin
  21.       odigit := chr( (n and 7) + ord('0') );
  22.    end;
  23. begin
  24.    coctal := '''\' + odigit(n shr 6) + odigit(n shr 3) + odigit(n) + '''';
  25.    toktype := strng;
  26. end;
  27.  
  28.  
  29. (********************************************************************)
  30. procedure getchar;
  31.    {consume the current char and get the next one}
  32. begin
  33.  
  34.    if read_include then
  35.    begin
  36.  
  37.       if eof(inclfd) then
  38.       begin
  39.          close(inclfd);
  40.  
  41.          read_include := false;
  42.          writeln(ofd[level]);
  43.  
  44.          if includeinclude then
  45.             writeln(ofd[level],'/* end of ',incl_name,' */')
  46.          else
  47.          begin
  48.             discard_nested;
  49.             write(con,^M^J,LJUST(' ',level*2+15),srcfiles[level],^M);
  50.          end;
  51.       end
  52.       else
  53.          read(inclfd, nextc);
  54.    end;
  55.  
  56.    if not read_include then
  57.    begin
  58.       if eof(infd) then
  59.          endfile;
  60.  
  61.       read(infd, nextc);
  62.    end;
  63.  
  64.    if nextc = ^J then
  65.    begin
  66.       inc(srclines[level]);
  67.  
  68.       if (srclines[level] mod 6) = 0 then
  69.          write(con,srcfiles[level],'(',srclines[level],')          '^M);
  70.  
  71.       abortcheck;
  72.    end;
  73.  
  74. end;
  75.  
  76.  
  77. (********************************************************************)
  78. function usec: char;
  79.    {use up the current character(return it) and get
  80.     the next one from the input stream}
  81. var
  82.    c: char;
  83. begin
  84.    c := nextc;
  85.    getchar;
  86.    usec := c;
  87. end;
  88.  
  89.  
  90. (********************************************************************)
  91. function newc(n: string40): string40;
  92.    {replace the current character with a different one and get the next
  93.     character from the input stream}
  94. var
  95.    c: char;
  96. begin
  97.    c := nextc;
  98.    getchar;
  99.    newc := n;
  100. end;
  101.  
  102.  
  103. (********************************************************************)
  104. procedure scan_ident;
  105.    {scan an identifier; output is ltok; nextc is first character following
  106.     the identifier; toktype = identifier;  this is the protocol for all of
  107.     the scan_xxxx procedures in the lexical analyzer}
  108. begin
  109.  
  110.    toktype := unknown;
  111.    ltok := '';
  112.  
  113.    repeat
  114.       case nextc of
  115.          'A'..'Z':
  116.             begin
  117.                if map_lower then
  118.                   nextc := chr( ord(nextc)+32 );
  119.                ltok := ltok + nextc;
  120.                getchar;
  121.             end;
  122.  
  123.          'a'..'z', '0'..'9', '_','@':
  124.             ltok := ltok + usec;
  125.  
  126.          else
  127.             toktype := identifier;
  128.       end;
  129.  
  130.    until toktype = identifier;
  131. end;
  132.  
  133.  
  134.  
  135. (********************************************************************)
  136. procedure scan_preproc;
  137.    {scan a tshell preprocessor directive;  same syntax as C already}
  138. begin
  139.    write(ofd[level],'#');
  140.  
  141.    repeat
  142.       write(ofd[level],nextc);
  143.       getchar;
  144.    until nextc = ^M;
  145.  
  146.    getchar;
  147.    writeln(ofd[level]);
  148.    toktype := unknown;
  149. end;
  150.  
  151.  
  152. (********************************************************************)
  153. procedure scan_number;
  154.    {scan a number;  this also processes #nnn character literals, which are
  155.     converted into octal character literals.  imbedded periods are processed,
  156.     and a special condition is noted for trailing periods.  this is needed
  157.     for scanning the ".." keyword when used after numbers.  an ungetchar
  158.     facility would be more general, but isn't needed anywhere else.
  159.     in pascal/mt+, #nnn is translated into nnnL }
  160. var
  161.    hasdot:  boolean;
  162.    octal:   boolean;
  163.    islong:  boolean;
  164.  
  165. begin
  166.    hasdot := false;
  167.    islong := false;
  168.    octal := false;
  169.    toktype := number;
  170.  
  171. (* check for preprocessor directives, character literals or long literals *)
  172.    if nextc = '#' then
  173.    begin
  174.       ltok := '';
  175.       if mt_plus then
  176.          islong := true
  177.       else
  178.          octal := true;
  179.    end;
  180.  
  181.    getchar;
  182.  
  183. (* check for preprocessor directives *)
  184.    if octal and (nextc in ['a'..'z']) then
  185.       scan_preproc
  186.    else
  187.  
  188.    repeat
  189.       case nextc of
  190.          '0'..'9':
  191.             ltok := ltok + usec;
  192.  
  193.          '.':
  194.             if hasdot then
  195.             begin
  196.                if ltok[length(ltok)] = '.' then
  197.                begin
  198.                   ltok[0] := pred(ltok[0]);  {remove trailing ., part of ..}
  199.                   if octal then
  200.                      ltok := coctal(atoi(ltok));
  201.                   extradot := true;
  202.                end;
  203.                exit;
  204.             end
  205.             else
  206.  
  207.             begin
  208.                hasdot := true;
  209.                ltok := ltok + usec;
  210.             end;
  211.  
  212.          else
  213.             begin
  214.                if octal then
  215.                   ltok := coctal(atoi(ltok))
  216.                else
  217.                if islong then
  218.                   ltok := ltok + 'L';
  219.                exit;
  220.             end;
  221.       end;
  222.  
  223.    until true=false;
  224. end;
  225.  
  226.  
  227. (********************************************************************)
  228. procedure scan_hat;
  229.    {scan tokens starting with ^ - returns ^X as a character literal 
  230.     corresponding to the specified control character.  returns ^ident as
  231.     an identifier with the leading ^ intact.  also scans ^. and ^[.}
  232. var
  233.    c: char;
  234.  
  235. begin
  236.    getchar;
  237.  
  238.    if (nextc = '.') or (nextc = '[') then
  239.       ltok := '^' + usec     {^. or ^[}
  240.    else
  241.  
  242.    if nextc in ['A'..'Z','a'..'z','@'..'_'] then
  243.    begin
  244.       ltok := nextc;
  245.       scan_ident;
  246.  
  247.       if length(ltok) = 1 then      {^c = control char}
  248.          ltok := coctal( ord(upcase(ltok[1])) - ord('@') )
  249.       else
  250.          ltok := '^' + ltok;        {^ident = pointer to ident}
  251.    end;
  252. end;
  253.  
  254.  
  255. (********************************************************************)
  256. procedure scan_dot;
  257.    {scans tokens starting with "."; knows about the 'extra dot' condition
  258.     that comes up in number scanning.  returns a token of either '.' or '..'}
  259. begin
  260.    getchar;
  261.  
  262.    if (nextc = '.') or extradot then
  263.    begin
  264.       ltok := '..';
  265.       extradot := false;
  266.    end;
  267.  
  268.    if nextc = '.' then
  269.       getchar;
  270. end;
  271.  
  272.  
  273. (********************************************************************)
  274. procedure scan_string;
  275.    {scans a literal string.  processes imbedded quotes ala pascal.  translates
  276.     the string into a C string with the proper escapes on imbedded quotes.
  277.     converts single character strings into character constants.  these are
  278.     sometimes converted back to strings when the parser needs to}
  279. begin
  280.  
  281.    toktype := unknown;
  282.    ltok := '"';
  283.    getchar;   {consume the open quote}
  284.  
  285.    repeat
  286.       if nextc in [^J,^M] then
  287.       begin
  288.          syntax('Closing quote expected (scan_string)');
  289.          exit;
  290.       end;
  291.  
  292.       if nextc = '''' then
  293.       begin
  294.          getchar;     {consume the quote}
  295.  
  296.          if nextc = '''' then
  297.             ltok := ltok + usec
  298.             {double quotes are coded as a single quote}
  299.          else
  300.  
  301.          begin        {end of string}
  302.             ltok := ltok + '"';
  303.             toktype := strng;
  304.          end;
  305.       end
  306.       else
  307.  
  308.       if nextc = '"' then
  309.          ltok := ltok + newc('\"')
  310.       else
  311.  
  312.       if nextc = '\' then
  313.          ltok := ltok + newc('\\')
  314.  
  315.       else
  316.          ltok := ltok + usec;
  317.  
  318.    until toktype = strng;
  319.  
  320.    if length(ltok) = 3 then
  321.    begin
  322.       ltok[1] := '''';
  323.       ltok[3] := '''';
  324.    end;
  325.  
  326.    if ltok = '"\""' then
  327.       ltok := '''"'''
  328.    else
  329.    if (ltok = '"''"') or (ltok = '''''''') then
  330.       ltok := '''\''''';
  331.  
  332. end;
  333.  
  334.  
  335. (********************************************************************)
  336. procedure scan_hex;
  337.    {scans a hex constant and returns it as a C style 0xHHHH literal}
  338. begin
  339.    getchar;  {consume the '$'}
  340.    ltok := '0x';
  341.  
  342.    while nextc in ['0'..'9', 'A'..'F', 'a'..'f'] do
  343.       ltok := ltok + usec;
  344.  
  345.    toktype := number;
  346. end;
  347.  
  348.  
  349. (********************************************************************)
  350. procedure scan_pragma;
  351.    {scans a turbo pascal compiler option and translates it into a general
  352.     "pragma" ','nd.  include directive is translated into the #include
  353.     ','nd.   returns with the first non-blank after the pragma}
  354. var
  355.    code: char;
  356.    prag: anystring;
  357.    arg:  anystring;
  358.  
  359. begin
  360.  
  361.    repeat
  362.       if nextc = ',' then
  363.          newline;
  364.  
  365.       getchar;   {consume the $ or ,}
  366.  
  367.       code := upcase(usec);
  368.       arg := usec;
  369.  
  370.       if arg = '+' then
  371.          arg := 'ON'
  372.       else
  373.  
  374.       if arg = '-' then
  375.          arg := 'OFF'
  376.       else
  377.  
  378.       begin        {decode numeric or string pragma params}
  379.          if arg = ' ' then
  380.             arg := '';
  381.          while not (nextc in [' ','*','}',',']) do
  382.             ltok := ltok + usec;
  383.          arg := arg;
  384.       end;
  385.  
  386.       case code of
  387.  
  388.          'I':  if (arg = 'ON') or (arg = 'OFF') then
  389.                   prag := '/* I(' + arg + ')' + ' */'
  390.                else
  391.                   begin
  392.                      prag := '#include "' + arg + '"' + ^M^J;
  393.                      {$I-} assign(inclfd, arg); 
  394.                            reset(inclfd); {$I+}
  395.                      if ioresult = 0 then
  396.                      begin
  397.                          read_include := true; 
  398.                          incl_name := arg;
  399.                          if not includeinclude then
  400.                          begin
  401.                             write(ofd[level],prag,'   ');
  402.                             enter_nested;
  403.                             srcfiles[level] := incl_name;
  404.                             srclines[level] := 0;
  405.                             write(con,^M^J,'':level*2+15,
  406.                                            srcfiles[level],^M);
  407.                          end;
  408.                      end;
  409.                   end;
  410.  
  411.          else  prag := '/* ' + code + '(' + arg + ')' + ' */';
  412.       end;
  413.  
  414.       write(ofd[level],prag,'   ');
  415.  
  416.       while nextc = ' ' do
  417.          getchar;
  418.  
  419.    until nextc <> ',';
  420.  
  421. end;
  422.  
  423.  
  424. (********************************************************************)
  425. procedure scan_curlycomment;
  426.    {processes a curly-brace enclosed comment}
  427. begin
  428.    getchar;   {consume the open comment}
  429.  
  430.    if nextc = '$' then
  431.    begin
  432.       scan_pragma;
  433.       if nextc = '}' then
  434.       begin
  435.          getchar;
  436.          exit;
  437.       end;
  438.    end;
  439.  
  440.    write(ofd[level],'  /* ');
  441.  
  442.    while nextc <> '}' do
  443.    begin
  444.       write(ofd[level],nextc);
  445.       getchar;
  446.    end;
  447.  
  448.    writeln(ofd[level],' */ ');
  449.    getchar;   {consume the close comment}
  450. end;
  451.  
  452.  
  453. (********************************************************************)
  454. procedure scan_parencomment;
  455.    {process a (* enclosed comment}
  456. begin
  457.    getchar;   {consume the *}
  458.  
  459.    if nextc = '$' then
  460.       scan_pragma;
  461.  
  462.    write(ofd[level],'/*');
  463.  
  464.    repeat
  465.       write(ofd[level],nextc);
  466.  
  467.       if nextc = '*' then
  468.       begin
  469.          getchar;
  470.  
  471.          if nextc = ')' then
  472.          begin
  473.             writeln(ofd[level],'/ ');
  474.             getchar;
  475.             exit;
  476.          end;
  477.       end
  478.       else
  479.          getchar;
  480.  
  481.    until true=false;
  482. end;
  483.  
  484.  
  485. (********************************************************************)
  486. procedure scan_blanks;
  487.    {scan white space.  this procedure sometimes passes whitespace to the
  488.     output.  it keeps track of the indentation of the current line so it
  489.     can be used by newline}
  490. var
  491.    linestart:     boolean;
  492.    indent:        anystring;
  493.    valid:         boolean;
  494.  
  495. begin
  496.    linestart := false;
  497.    indent := '';
  498.    valid := false;
  499.  
  500.    repeat
  501.  
  502.       case nextc of
  503.          ^J,^M:  begin
  504.                     if nospace=false then
  505.                        write(ofd[level],nextc);
  506.                     indent := '';
  507.                     linestart := true;
  508.                     getchar;
  509.                  end;
  510.  
  511.          ' ',^I,^@,^L:
  512.                  indent := indent + usec;
  513.  
  514.          '#':    if linestart then
  515.                  begin
  516.                     write(ofd[level],indent);       {pass preprocessor directives}
  517.                     indent := '';            {without change (single-line only)}
  518.                     repeat
  519.                        write(ofd[level],nextc);
  520.                        getchar;
  521.                     until nextc = ^M;
  522.                     getchar;
  523.                     writeln(ofd[level]);
  524.                  end
  525.                  else
  526.                     valid := true;
  527.  
  528.          else
  529.                  valid := true;
  530.       end;
  531.  
  532.    until valid;
  533.  
  534.    if linestart then
  535.    begin
  536.       spaces := indent;
  537.       if nospace=false then
  538.          write(ofd[level],spaces);
  539.    end;
  540. end;
  541.  
  542.  
  543. (********************************************************************)
  544. procedure scan_tok;
  545.    {scans the next lexical token; returns the token in ltok and toktype}
  546. begin
  547.    scan_blanks;
  548.  
  549.    toktype := unknown;
  550.    ltok := nextc;
  551.  
  552.    case nextc of
  553.       'a'..'z', 
  554.       '_', 'A'..'Z': scan_ident;
  555.  
  556.       '''':          scan_string;
  557.  
  558.       '0'..'9':      scan_number;
  559.  
  560.       '#':           begin
  561.                         scan_number;
  562.                         if toktype = unknown then
  563.                            scan_tok;         {in case of #directive}
  564.                      end;
  565.  
  566.       '$':           scan_hex;
  567.  
  568.       '<':           begin
  569.                         getchar;
  570.                         if (nextc = '>') or (nextc = '=') then
  571.                            ltok := '<' + usec;
  572.                      end;
  573.  
  574.       '>':           begin
  575.                         getchar;
  576.                         if nextc = '=' then
  577.                            ltok := '>' + usec;
  578.                      end;
  579.  
  580.       ':':           begin
  581.                         getchar;
  582.                         if nextc = '=' then
  583.                            ltok := ':' + usec;
  584.                      end;
  585.  
  586.       '^':           scan_hat;
  587.  
  588.       '.':           scan_dot;
  589.  
  590.       '{':           begin
  591.                         scan_curlycomment;
  592.                         scan_tok;
  593.                      end;
  594.  
  595.       '(':       begin
  596.                         getchar;
  597.                         if nextc = '*' then
  598.                         begin
  599.                            scan_parencomment;
  600.                            scan_tok;
  601.                         end;
  602.                      end;
  603.  
  604.       else           getchar;   {consume the unknown char}
  605.    end;
  606. end;
  607.  
  608.  
  609. (********************************************************************)
  610. procedure gettok;
  611.    {get the next input token;  this is the top level of the lexical analyzer.
  612.     it returns ltok, tok(ltok in upper case), toktype.  it translates BEGIN
  613.     and END into braces; it checks for statement and section keywords}
  614. var
  615.    i:             integer;
  616.  
  617. begin
  618.  
  619.    scan_tok;
  620.    tok := ltok;
  621.  
  622.    if toktype = identifier then
  623.    begin
  624.       stoupper(tok);
  625.  
  626.       if tok = 'BEGIN' then
  627.       begin
  628.          tok := '{';
  629.          ltok := tok;
  630.          toktype := keyword;
  631.          exit;
  632.       end;
  633.  
  634.       if tok = 'END' then
  635.       begin
  636.          tok := '}';
  637.          ltok := tok;
  638.          toktype := keyword;
  639.          exit;
  640.       end;
  641.  
  642.       (* check for statement keywords *)
  643.       for i := 1 to nkeywords do
  644.          if tok = keywords[i] then
  645.          begin
  646.             toktype := keyword;
  647.             exit;
  648.          end;
  649.    end;
  650. end;
  651.  
  652.  
  653. (********************************************************************)
  654. function usetok: string80;
  655.    {return (use) and consume current token}
  656. var
  657.    tv: string80;
  658. begin
  659.    tv := ltok;
  660.    gettok;
  661.    usetok := tv;
  662. end;
  663.  
  664.  
  665.